<template>
  <a-drawer
    :visible="visible"
    title="声音克隆"
    @close="closeChange"
    :width="800"
  >
    <template v-if="agreement || id">
      <a-form layout="vertical">
        <a-form-item
          v-if="requiredInformationData.voice_name"
          v-bind="validateInfos.voice_name"
        >
          <template #label>
            <span class="label">
              {{ requiredInformationData.voice_name.label }}
            </span>
            <a-tooltip>
              <template #title>
                {{ requiredInformationData.voice_name.tip.join("") }}
              </template>
              <question-circle-outlined
                v-if="requiredInformationData.voice_name.tip.length"
              />
            </a-tooltip>
          </template>
          <a-input
            v-model:value="modelRef.voice_name"
            :placeholder="'请输入' + requiredInformationData.voice_name.label"
            :maxlength="requiredInformationData.voice_name.max"
            @change="voiceNameChange"
            :disabled="
              notSupported || modifySomeInformation || !informationChanges
            "
          />
        </a-form-item>

        <a-form-item
          v-if="requiredInformationData.voice_id"
          v-bind="validateInfos.voice_id"
        >
          <template #label>
            <span class="label">
              {{ requiredInformationData.voice_id.label }}
            </span>
            <a-tooltip>
              <template #title>
                {{ requiredInformationData.voice_id.tip.join("") }}
              </template>
              <question-circle-outlined
                v-if="requiredInformationData.voice_id.tip.length"
              />
            </a-tooltip>
          </template>
          <a-input
            v-model:value="modelRef.voice_id"
            :placeholder="'请输入' + requiredInformationData.voice_id.label"
            :maxlength="requiredInformationData.voice_id.max"
            :disabled="
              notSupported || modifySomeInformation || !informationChanges
            "
          />
        </a-form-item>

        <a-form-item
          v-if="requiredInformationData.gender"
          v-bind="validateInfos.gender"
        >
          <template #label>
            <span class="label">
              {{ requiredInformationData.gender.label }}
            </span>
            <a-tooltip>
              <template #title>
                {{ requiredInformationData.gender.tip.join("") }}
              </template>
              <question-circle-outlined
                v-if="requiredInformationData.gender.tip.length"
              />
            </a-tooltip>
          </template>
          <a-select
            v-model:value="modelRef.gender"
            style="width: 100%"
            :placeholder="'请选择' + requiredInformationData.gender.label"
            :options="requiredInformationData.gender.select"
            allowClear
            :disabled="
              notSupported || modifySomeInformation || !informationChanges
            "
          ></a-select>
        </a-form-item>

        <a-form-item v-if="requiredInformationData.scenario">
          <template #label>
            <span class="label">
              {{ requiredInformationData.scenario.label }}
            </span>
            <a-tooltip>
              <template #title>
                {{ requiredInformationData.scenario.tip.join("") }}
              </template>
              <question-circle-outlined
                v-if="requiredInformationData.scenario.tip.length"
              />
            </a-tooltip>
          </template>
          <a-select
            v-model:value="modelRef.scenario"
            style="width: 100%"
            :placeholder="'请选择' + requiredInformationData.scenario.label"
            :options="requiredInformationData.scenario.select"
            allowClear
            @change="scenarioChange"
            :disabled="
              notSupported || (!modifySomeInformationd && !informationChanges)
            "
          ></a-select>
        </a-form-item>

        <a-form-item v-if="modelRef.scenario">
          <template #label>
            <span class="label"> 请选择本次朗读的文本 </span>
          </template>
          <a-select
            v-model:value="modelRef.text"
            style="width: 100%"
            :placeholder="'请选择本次朗读的文本'"
            :options="demonstrationList"
            allowClear
            @change="textChange"
            :disabled="
              notSupported || (!modifySomeInformation && !informationChanges)
            "
          ></a-select>
        </a-form-item>

        <a-form-item v-if="requiredInformationData.voice_desc">
          <template #label>
            <span class="label">
              {{ requiredInformationData.voice_desc.label }}
            </span>
            <a-tooltip>
              <template #title>
                {{ requiredInformationData.voice_desc.tip.join("") }}
              </template>
              <question-circle-outlined
                v-if="requiredInformationData.voice_desc.tip.length"
              />
            </a-tooltip>
          </template>
          <a-input
            v-model:value="modelRef.voice_desc"
            :placeholder="'请输入' + requiredInformationData.voice_desc.label"
            :maxlength="requiredInformationData.voice_desc.max"
            :disabled="
              notSupported || modifySomeInformation || !informationChanges
            "
          />
        </a-form-item>

        <a-form-item
          v-if="requiredInformationData.authentication_audio"
          v-bind="validateInfos.authentication_audio"
        >
          <template #label>
            <span class="label">
              {{ requiredInformationData.authentication_audio.label }}
            </span>
            <a-tooltip>
              <template #title>
                {{ requiredInformationData.authentication_audio.tip.join("") }}
              </template>
              <question-circle-outlined
                v-if="requiredInformationData.authentication_audio.tip.length"
              />
            </a-tooltip>
          </template>
          <div
            v-if="!modelRef.authentication_audio"
            class="upload-dragger"
            @click="
              handleUploadChange(
                requiredInformationData.authentication_audio.allow_extension,
                'authentication_audio'
              )
            "
          >
            <div>
              <cu-icon class="icon-upload" type="icon-shangchuan"></cu-icon>
            </div>
            <div>请上传一段音频,用于声音克隆</div>
            <div style="color: #939393">点击此区域上传</div>
          </div>
          <div
            class="select_voice_style have_voice"
            v-if="modelRef.authentication_audio"
          >
            <DeleteOutlined class="del_icon" @click="delVoice"></DeleteOutlined>
            <!-- 音频暂停状态 -->
            <PauseCircleOutlined
              class="voice_icon"
              v-if="voiceState"
              @click="playVoice"
            />
            <!-- 音频播放状态 -->
            <PlayCircleOutlined v-else @click="playVoice" class="voice_icon">
            </PlayCircleOutlined>
            <audio
              ref="voice"
              @ended="endedChange"
              @play="onPlayChange"
              @pause="onPauseChange"
              :src="modelRef.authentication_audio"
              controls
            ></audio>
          </div>
        </a-form-item>
        <a-form-item
          v-if="requiredInformationData.record_url"
          v-bind="validateInfos.record_url"
        >
          <template #label>
            <span class="label">
              {{ requiredInformationData.record_url.label }}
            </span>
            <a-tooltip>
              <template #title>
                {{ requiredInformationData.record_url.tip.join("") }}
              </template>
              <question-circle-outlined />
            </a-tooltip>
          </template>
          <div
            v-if="!modelRef.record_url"
            class="upload-dragger"
            @click="
              handleUploadChange(
                requiredInformationData.record_url.allow_extension,
                'record_url'
              )
            "
          >
            <div>
              <cu-icon class="icon-upload" type="icon-shangchuan"></cu-icon>
            </div>
            <div>请上传一段音频,用于声音克隆</div>
            <div style="color: #939393">点击此区域上传</div>
          </div>
          <div class="select_voice_style have_voice" v-if="modelRef.record_url">
            <DeleteOutlined
              class="del_icon"
              @click="delRecordUrlVoice"
            ></DeleteOutlined>
            <!-- 音频暂停状态 -->
            <PauseCircleOutlined
              class="voice_icon"
              v-if="playRecordUrlVoice"
              @click="playRecordUrlVoiceClick"
            />
            <!-- 音频播放状态 -->
            <PlayCircleOutlined
              v-else
              @click="playRecordUrlVoiceClick"
              class="voice_icon"
            >
            </PlayCircleOutlined>
            <audio
              ref="voiceRecordUrl"
              @ended="endedRecordUrlChange"
              @play="onPlayRecordUrlChange"
              @pause="onPauseRecordUrlChange"
              :src="modelRef.record_url"
              controls
            ></audio>
          </div>
        </a-form-item>
      </a-form>
    </template>
    <template v-else>
      <CloningProcess />
    </template>
    <template #footer>
      <a-row
        align="middle"
        :justify="!agreement && !id ? 'space-between' : 'end'"
      >
        <a-col v-if="!agreement && !id">
          <a-checkbox v-model:checked="checked">
            我已阅读并同意 <a>《声音克隆协议》</a>
          </a-checkbox>
        </a-col>
        <a-col>
          <a-row align="middle" style="width: 100%">
            <div style="color: red; margin-right: 50px" v-if="statusText && id">
              {{ statusText }}
            </div>
            <a-button
              v-if="!agreement && !id"
              :disabled="!checked"
              type="primary"
              @click="nextStep"
            >
              下一步
            </a-button>
            <a-button
              v-else
              type="primary"
              :loading="loading"
              :disabled="statusText"
              @click="startCloning"
            >
              开始克隆
            </a-button>
          </a-row>
        </a-col>
      </a-row>
    </template>
    <!-- 素材库 -->
    <ChooseMaterial
      useType="AIdigitalHuman"
      material_type="audio"
      :extension="extension"
      :isClip="false"
      :multiple="false"
      :visible="chooseMaterialVisible"
      @close="closeChooseMaterial"
    />

    <notVoiceNumDialog
      :voiceNum="voiceNum"
      @handleOk="handleOk"
      ref="notVoiceNumDialogRef"
    ></notVoiceNumDialog>
  </a-drawer>
</template>

<script>
import { ref, watch, toRefs, defineComponent, reactive, computed } from "vue";
import request from "@/common/utils/request";
import { Form, message } from "ant-design-vue";
import {
  PaperClipOutlined,
  DeleteOutlined,
  QuestionCircleOutlined,
  PlayCircleOutlined,
  PauseCircleOutlined,
} from "@ant-design/icons-vue";
// 克隆流程
import CloningProcess from "./CloningProcess.vue";
// 素材库
import ChooseMaterial from "@/views/shotstack/EditingCenter/modules/bottomSet/components/chooseMaterial.vue";
// 工具引入
import _ from "lodash";

import notVoiceNumDialog from "./notVoiceNumDialog.vue";

const useForm = Form.useForm;

export default defineComponent({
  name: "SoundCloningDrawer ",
  components: {
    ChooseMaterial,
    DeleteOutlined,
    PaperClipOutlined,
    QuestionCircleOutlined,
    CloningProcess,
    PlayCircleOutlined,
    PauseCircleOutlined,
    notVoiceNumDialog,
  },
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    id: {
      type: [Number, String],
      default: "",
    },
  },
  setup(props, { emit }) {
    // 提示声音次数不足组件
    const notVoiceNumDialogRef = ref(null);
    const state = reactive({
      count: 0,
      checked: false,
      agreement: false,
      extension: "",
      chooseMaterialVisible: false,
      uploadType: "",
      fileList: [],
      requiredInformationData: {},
      demonstrationList: [],
      demonstrationListAll: [],
      recordUrlList: [],
      authenticationList: [],
      loading: false,
      status: null,
      voiceState: false,
      playRecordUrlVoice: false,
      // 剩余人声克隆次数
      voiceNum: 0,
    });

    const modelRef = reactive({
      authentication_audio: "",
      gender: undefined,
      record_url: "",
      scenario: undefined,
      voice_desc: "",
      voice_id: "",
      voice_name: "",
      text: undefined,
      demo_audio: "",
      audio_id: "",
    });
    const rulesRef = reactive({
      voice_id: [
        {
          required: true,
          message: "请输入自定义的声音 Id",
        },
      ],
      voice_name: [
        {
          required: true,
          message: "请输入声音名称",
        },
      ],
      gender: [
        {
          required: true,
          message: "请选择性别",
        },
      ],
      // authentication_audio: [
      //   {
      //     required: true,
      //     message: "请上传声音认证音频",
      //   },
      // ],
      // record_url: [
      //   {
      //     required: true,
      //     message: "请上传录音文件",
      //   },
      // ],
    });
    const nextStep = () => {
      if (state.checked) {
        state.agreement = true;
      } else {
        state.agreement = false;
      }
    };
    // 防抖
    const debounce = (func, wait = 2000, immediate = false) => {
      if (state.timeout !== null) clearTimeout(state.timeout);
      // 立即执行，此类情况一般用不到
      if (immediate) {
        typeof func === "function" && func();
      } else {
        // 设置定时器，当最后一次操作后，timeout不会再被清除，所以在延时wait毫秒后执行func回调方法
        state.timeout = setTimeout(function () {
          typeof func === "function" && func();
        }, wait);
      }
    };

    // 声音名字输入回调
    const voiceNameChange = () => {
      debounce(() => {
        getVoiceIdCheck(modelRef.voice_name);
      }, 500);
    };

    // 场景变换回调
    const scenarioChange = (e) => {
      modelRef.text = undefined;
      getDemonstrationist(e);
    };

    // 选择本次朗读的文本
    const getDemonstrationist = (scenario) => {
      request
        .get("/work_ai", "/voice/customized/demonstration/list", { scenario })
        .then((res) => {
          state.demonstrationList = res.result.demonstrationList.map((item) => {
            return {
              label: item.Text,
              value: item.AudioId,
            };
          });
          state.demonstrationListAll = res.result.demonstrationList;
          if (!props.id) {
            modelRef.text = state.demonstrationListAll[0].Text;
            modelRef.demo_audio = state.demonstrationListAll[0].DemoAudio;
            modelRef.audio_id = state.demonstrationListAll[0].AudioId;
          }
        });
    };

    const textChange = (e) => {
      if (e) {
        modelRef.text = state.demonstrationListAll.find(
          (item) => item.AudioId == e
        ).Text;
        modelRef.demo_audio = state.demonstrationListAll.find(
          (item) => item.AudioId == e
        ).DemoAudio;
        modelRef.audio_id = e;
      } else {
        modelRef.text = undefined;
        modelRef.demo_audio = "";
        modelRef.audio_id = "";
      }
    };

    const getVoiceIdCheck = (voice_name) => {
      if (!voice_name) {
        return;
      }
      request
        .get("/work_ai", "/voice/customized/voiceId/check", { voice_name })
        .then((res) => {
          modelRef.voice_id = res.result.voice_id;
        });
    };

    // upload上传
    const handleUploadChange = (extension, type) => {
      if (statusText.value) {
        message.warn(statusText.value);
        return;
      }
      if (state.status == 6) {
        message.warn("训练失败,不支持修改");
        return;
      }
      if (extension) {
        state.extension = extension
          .map((extension) => "." + extension)
          .join(",");
      }
      state.uploadType = type;
      state.chooseMaterialVisible = true;
    };

    // 音频播放
    const voice = ref(null);
    const playVoice = () => {
      if (voice.value) {
        if (voice.value.paused) {
          voice.value.play(); // 如果音频是暂停的，则播放
          state.voiceState = true;
        } else {
          voice.value.pause(); // 如果音频正在播放，则暂停
          state.voiceState = false;
        }
      }
    };

    // 音频开始回调
    const onPlayChange = () => {
      console.log("开始");
      state.voiceState = true;
    };

    // 音频暂停回调
    const onPauseChange = () => {
      console.log("暂停");
      state.voiceState = false;
    };

    // 音频结束回调
    const endedChange = () => {
      console.log("结束");
      state.voiceState = false;
    };

    //删除所选音频
    const delVoice = () => {
      modelRef.authentication_audio = "";
    };

    const voiceRecordUrl = ref(null);
    const playRecordUrlVoiceClick = () => {
      console.log("录音文件");
      if (voiceRecordUrl.value) {
        if (voiceRecordUrl.value.paused) {
          voiceRecordUrl.value.play(); // 如果音频是暂停的，则播放
          state.playRecordUrlVoice = true;
        } else {
          voiceRecordUrl.value.pause(); // 如果音频正在播放，则暂停
          state.playRecordUrlVoice = false;
        }
      }
    };

    const onPlayRecordUrlChange = () => {
      state.playRecordUrlVoice = true;
    };
    // 音频暂停回调
    const onPauseRecordUrlChange = () => {
      console.log("暂停");
      state.playRecordUrlVoice = false;
    };

    // 音频结束回调
    const endedRecordUrlChange = () => {
      console.log("结束");
      state.playRecordUrlVoice = false;
    };

    //删除所选音频
    const delRecordUrlVoice = () => {
      modelRef.record_url = "";
    };

    const getVoiceTime = async () => {
      if (props.id) {
        handleOk();
        return;
      }
      const res = await request.get(
        "/work_ai",
        "/voice/customized/config/get",
        {
          number: "1",
        }
      );
      state.voiceNum = res.customizedVoiceNum;
      notVoiceNumDialogRef.value.showModal();
    };

    // 确认消耗, 进行合成
    const handleOk = () => {
      state.loading = true;
      console.log(modelRef, "modelRef");
      if (props.id) {
        modelRef.id = props.id;
        request
          .put("/work_ai", "/voice/customizedJob/update", modelRef)
          .then((res) => {
            if (res?.code && res.code != 1000) {
              throw new Error(res.msg);
            }
            state.loading = false;
            message.success("修改成功");
            emit("submitChange");
            console.log(res);
          })
          .catch((err) => {
            message.error(err.message || "合成失败");
            state.loading = false;
          });
        return;
      }
      // 新建 确保没有id 属性
      delete modelRef.id;
      request
        .post("/work_ai", "/voice/customized/create", modelRef)
        .then((res) => {
          console.log(res, "声音创建");

          if (res?.code && res.code != 1000) {
            throw new Error(res.msg);
          }
          state.loading = false;
          message.success("提交成功");
          emit("submitChange");
          console.log(res);
        })
        .catch((err) => {
          message.error(err.message || "合成失败");
          state.loading = false;
        });
    };

    // 开始克隆
    const startCloning = () => {
      // 开始合成 表单校验之后 开始次数消耗校验
      validate().then(async () => {
        getVoiceTime();
      });
    };

    const { resetFields, validate, validateInfos } = useForm(
      modelRef,
      rulesRef
    );

    // 选择素材回调
    const closeChooseMaterial = (data) => {
      if (data) {
        if (state.uploadType == "authentication_audio") {
          state.authenticationList = [data];
          modelRef.authentication_audio = data.material_url;
        }
        if (state.uploadType == "record_url") {
          state.recordUrlList = [data];
          modelRef.record_url = data.material_url;
        }
      }
      state.chooseMaterialVisible = false;
    };

    const deleteAudio = (type) => {
      state.uploadType = type;
      if (state.uploadType == "authentication_audio") {
        state.authenticationList = [];
        modelRef.authentication_audio = "";
      }
      if (state.uploadType == "record_url") {
        state.recordUrlList = [];
        modelRef.record_url = "";
      }
      state.fileList = [];
    };

    const getRequiredInformation = () => {
      request
        .get("/work_ai", "/voice/customized/required/information")
        .then((res) => {
          state.requiredInformationData = res.result;
          modelRef.scenario =
            state.requiredInformationData?.scenario?.select[0].value;
          getDemonstrationist(modelRef.scenario);
        });
    };

    const setModelRef = (state) => {
      for (let key in state) {
        if (Object.hasOwn(modelRef, key)) {
          modelRef[key] = state[key];
        }
      }
    };

    const getCustomizedInfoDetail = () => {
      request
        .get("/work_ai", "/voice/customizedInfo/detail", { id: props.id })
        .then((res) => {
          state.status = res.result.status;
          getDemonstrationist(res.result.scenario);
          setModelRef(res.result);
          modelRef.text = res.result.demo_text || undefined;

          if (res.result.authentication_audio) {
            state.authenticationList = [res.result.authentication_audio];
            modelRef.authentication_audio = res.result.authentication_audio;
          } else {
            state.authenticationList = [];
            modelRef.authentication_audio = "";
          }

          if (res.result.record_url) {
            state.recordUrlList = [res.result.record_url];
            modelRef.record_url = res.result.record_url;
          } else {
            state.recordUrlList = [];
            modelRef.record_url = "";
          }
        });
    };

    // 未初始化+初始化失败 （status = 0 || status = 7） 支持 所有信息变更
    const informationChanges = computed(() => {
      if (!props.id) {
        return true;
      }
      return state.status == 0 || state.status == 7;
    });

    // 音频检测失败（status = 8） 支持修改 部分信息 认证音频[authentication_audio]、RecordUrl 对应的音频序号[audio_id]、录音URL[record_url]、示例URL[demo_audio]、示例文本[text]
    const modifySomeInformation = computed(() => {
      if (!props.id) {
        return false;
      }
      return state.status == 8;
    });

    // 重新提交 但不支持信息修改
    const notSupported = computed(() => {
      if (!props.id) {
        return false;
      }
      return (
        state.status == 6 ||
        (state.status == 2 && modelRef.audio_pass_status == 2)
      );
    });

    const statusText = computed(() => {
      if (!props.id) {
        return false;
      }
      if (state.status == 2) {
        return "音频检测中, 信息不允许变更!";
      }
      if (state.status == 3) {
        return "提交训练,待训练, 信息不允许变更!";
      }
      if (state.status == 4) {
        return "训练中, 信息不允许变更!";
      }
      if (state.status == 5) {
        return "训练成功, 信息不允许变更!";
      }
      if (props.id && state.status == 2 && modelRef.audio_pass_status == 2) {
        return "训练成功, 信息不允许变更!";
      }
    });

    const closeChange = () => {
      resetFields();
      emit("closeChange");
    };

    watch(
      () => props.visible,
      (val) => {
        if (val) {
          getRequiredInformation();
          if (props.id) {
            getCustomizedInfoDetail();
          }
        } else {
          state.checked = false;
          state.agreement = false;
          state.authenticationList = [];
          modelRef.authentication_audio = "";
          state.recordUrlList = [];
          modelRef.record_url = "";
        }
      }
    );

    return {
      ...toRefs(state),
      closeChange,
      handleOk,
      notVoiceNumDialogRef,
      validateInfos,
      resetFields,
      modelRef,
      nextStep,
      startCloning,
      handleUploadChange,
      closeChooseMaterial,
      deleteAudio,
      voiceNameChange,
      scenarioChange,
      textChange,
      informationChanges,
      modifySomeInformation,
      notSupported,
      statusText,
      voice,
      endedChange,
      onPauseChange,
      onPlayChange,
      playVoice,
      delVoice,
      delRecordUrlVoice,
      endedRecordUrlChange,
      onPauseRecordUrlChange,
      onPlayRecordUrlChange,
      playRecordUrlVoiceClick,
      voiceRecordUrl,
    };
  },
});
</script>

<style lang="less" scoped>
.label {
  font-weight: 600;
  margin-right: 5px;
}

.audio-requirements {
  background: #f7f8fa;
  padding: 10px;
  margin-bottom: 15px;
}

.icon-upload {
  font-size: 55px;
}

.upload-dragger {
  width: 100%;
  height: 130px;
  border: 1px dashed rgba(222, 222, 222, 1);
  background: #fafafa;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  transition: all ease-out 0.3s;

  &.upload-dragger:hover {
    border: 1px dashed rgba(82, 151, 255, 1);
  }
}

.file-list {
  padding-left: 5px;
  margin: 5px 0;

  &.file-list:hover {
    background: #f5f5f5;
  }

  .delete-outlined {
    color: red;
  }
}

.select_voice_style {
  height: 200px;
  width: 100%;
  border-radius: 8px;
  border: 1px solid #c0c0c0;
  display: flex;

  &:hover {
    border-color: var(--ss-primary-color-hover);
    color: var(--ss-primary-color-hover);
  }
}

// 选择了音频的样式
.have_voice {
  // flex-direction: column;
  // align-items: center;
  // justify-content: space-between;
  padding: 15px;
  position: relative;
  transition: all 0.3s;

  .voice_icon {
    color: #666666;
    cursor: pointer;
    font-size: 50px;
    position: absolute;
    top: 35%;
    left: 50%;
    transform: translate(-50%, -50%);

    &:hover {
      color: var(--ss-primary-color-hover);
    }
  }

  .del_icon {
    color: #666666;
    cursor: pointer;
    position: absolute;
    right: 10px;
    top: 10px;
    font-size: 23px;

    &:hover {
      color: var(--ss-error-color);
    }
  }

  audio {
    width: calc(100% - 30px);
    position: absolute;
    bottom: 15px;
    left: 15px;
  }
}
</style>
